<!-- 可配置列的表格 -->
<template>
  <div>
    <div v-if="isEmpty">
      <el-empty description="表格数据未设置"></el-empty>
    </div>
    <div v-else>
      <el-table :data="list" @row-dblclick="rowDoubleClick">
        <el-table-column width="60">
          <template #header>
            <el-button :icon="Setting" link @click="openSetting" v-if="isAdmin" />
            <span v-else>#</span>
          </template>
          <template #default="scope">
            {{ scope.$index + 1 }}
          </template>
        </el-table-column>
        <template v-for="(item, index) in showColumn?.filter((obj) => obj.isShow)" :key="index">
          <el-table-column :label="item.label" :prop="item.prop" :width="item.width" />
        </template>
      </el-table>
    </div>

    <el-dialog title="表格配置" v-model="isShowDialog" @close="isShowDialog = false" width="40%"
      :close-on-click-modal="false" draggable>
      <el-table :data="settingColumn" style="width: 100%">
        <el-table-column label="列字段" prop="prop" />
        <el-table-column label="标题">
          <template #default="{ row }">
            <el-input v-model="row.label" />
          </template>
        </el-table-column>

        <el-table-column label="宽度px" width="90px">
          <template #default="{ row }">
            <el-input v-model="row.width" placeholder="自动" />
          </template>
        </el-table-column>

        <el-table-column label="是否显示" width="80px">
          <template #default="{ row }">
            <el-checkbox v-model="row.isShow" />
          </template>
        </el-table-column>

        <el-table-column label="显示顺序" width="80px">
          <template #default="{ row }">
            <el-input-number :controls="false" style="width: 100%" v-model="row.sorting" :precision="0" />
          </template>
        </el-table-column>
      </el-table>
      <template #footer>
        <el-button @click="doDefault">恢复默认值</el-button>
        <el-button @click="update" type="primary">确认修改</el-button>
      </template>
    </el-dialog>
  </div>
</template>

<script lang="ts" setup>
import { CustomTableDto } from "./dto.js";
import { Setting } from '@element-plus/icons-vue'
//支持自定义列的表格
defineOptions({
  name: "MkCustomTable",
});
const props = defineProps({
  //数据
  list: { type: Array, default: () => [] },
  //默认列配置
  defaultColumn: {
    type: Array<CustomTableDto>,
    default: () => [],
    required: true,
  },
  //表格类型
  tableId: { type: String, default: undefined, required: true },
});
//表格列是否空
const isEmpty = ref<Boolean>(true);
//要显示的列及属性
const showColumn = ref<Array<CustomTableDto>>();
// 登录用户是否管理员，管理员才可以修改表格配置
const isAdmin = ref<Boolean>(true);

//#region 列设置对话框相关操作
//对话框列的配置
const settingColumn = ref<Array<CustomTableDto>>();
const isShowDialog = ref<boolean>(false);

//打开设置对话框
const openSetting = () => {
  isShowDialog.value = true;
  if (showColumn.value) {
    settingColumn.value = mergeArrays(props.defaultColumn, showColumn.value);
  }
};

//确认修改
const update = () => {
  if (settingColumn.value) {
    //此处后续改为调用接口存储
    saveConfig(JSON.stringify(settingColumn.value));
    setShowColumn(); //重新读取配置文件
  }
  isShowDialog.value = false;
};

//恢复默认值
const doDefault = () => {
  settingColumn.value = mergeArrays(props.defaultColumn, []);
};
//#endregion

//#region 表格操作
//设置主表格中要显示的列,从缓存获取
const setShowColumn = () => {
  showColumn.value = [];
  if (isNull(props.defaultColumn)) {
    isEmpty.value = true;
    return;//没有默认列配置,直接返回
  } else {
    isEmpty.value = false;
  }
  let config = getConfig();
  if (!isNull(props.tableId) && config != null && config != undefined && config != "") {
    let settingArr = JSON.parse(config);
    showColumn.value = mergeArrays(props.defaultColumn, settingArr);
  } else {
    showColumn.value = props.defaultColumn;
    for (var i = 0; i < showColumn.value.length; i++) {
      showColumn.value[i].sorting = i + 1;
      showColumn.value[i].isShow = true;
    }
  }
};

//在默认数组中，获取已设置数组的配置
//@param defaultArr 默认数组
//@param settingArr 已设置数组
const mergeArrays = function (defaultArr: CustomTableDto[], settingArr: CustomTableDto[]): any[] {
  const mergedArray: CustomTableDto[] = [];
  //
  for (const itemA of defaultArr) {
    const itemB = settingArr.find((item) => item.prop === itemA.prop);
    if (!isNull(itemB) && itemB) {
      itemA.label = itemB.label;
      itemA.width = itemB.width;
      itemA.isShow = itemB.isShow;
      itemA.sorting = itemB.sorting;
    } else {
      itemA.width = undefined;
      itemA.isShow = true;
      itemA.sorting = 99;
    }

    mergedArray.push(deepClone(itemA) as CustomTableDto);
  }
  mergedArray.sort((a, b) => {
    return (a.sorting ?? 99) - (b.sorting ?? 99);
  });

  return mergedArray;
};

//保存配置
const saveConfig = (config: string) => {
  const configId = `customtableid${props.tableId}`;
  localStorage.setItem(configId, config)
}

//读取配置
const getConfig = () => {
  const configId = `customtableid${props.tableId}`;
  return localStorage.getItem(configId)
}

//定义回调函数
let emits = defineEmits(['row-dblclick'])

//双击列表数据打开弹框
const rowDoubleClick = (row: any) => {
  emits('row-dblclick', row) //调用父组件执行查询
}

onMounted(() => {
  setShowColumn();
  // 判断当前用户是否为管理员
  isAdmin.value = true
});
//#endregion

/**
 * 判断是否为空
 * 判断对象，数组，字符串是否为空，例如:  undefined , null , '' , '   ' , {}  , [] 全部判断为空
 * @param value
 * @returns
 */
function isNull(value: any) {
  if (value === undefined || value === null) {
    return true;
  }
  if (typeof value === 'string' && value.trim() === '') {
    return true;
  }
  if (typeof value === 'number' && Number.isNaN(value)) {
    return true;
  }
  if (Array.isArray(value) && value.length === 0) {
    return true;
  }
  if (value.constructor === Object && Reflect.ownKeys(value).length === 0) {
    return true;
  }
  return false;
}

/**
 * @param src  传入对象，对对象进行深克隆
 * @returns 返回深克隆后的对象（数据相同指针不同）
 */
function deepClone(src: object) {
  if (typeof src === 'object' && src) {
    let target = Array.isArray(src) ? [] : {}
    for (const key in src) {
      (target as any)[key] = deepClone((src as any)[key])
    }
    return target
  } else {
    return src
  }
}

/*
//CustomTableDto定义如下
export class CustomTableDto {
  id?: number
  prop: string = ''
  label: string = ''
  width?: string
  sorting?: number = 100
  isShow?: boolean
}
//使用方法如下
<c-custom-table :defaultColumn="defaultColumn" :list="infoList" tableId="EnumList" @row-dblclick="rowDoubleClick" />
//定义默认列
const defaultColumn: Array<CustomTableDto> = [
  { label: '枚举类型', prop: 'enumType' },
  { label: '枚举名', prop: 'enumName' },
  { label: '枚举值', prop: 'enumValue' },
  { label: '备注', prop: 'remark' }]
*/
</script>

<style lang="scss" scoped></style>
